/*
SSD1289 3.2" TFT LCD Functions for PIC32MX795F512L PMP
Copyright (C) 2012 Craig Dawson, Aaron Mohtar, Craig Peacock

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "lcdDraw.h"

//-------------------------------
// Usage: lcdDrawHorizontalLine(0, 10, 239, 10, RED);
// Draws a Horizontal line from (x1,y1) to (x2,y1) of the colour specified
// y2 is ignored
//-------------------------------
void lcdDrawHorizontalLine(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int colour)
{
    unsigned int i;

    // If start of line is greater than end, reverse
    if (x1 > x2)
    {
        i = x1;
        x1 = x2;
        x2 = i;
    }

    lcdSetAddress(x1, y1, x2, y1);

    PMADDR = DATA;

    for (i = x1; i <= x2; i++)
        PMDIN = colour;
}

//-------------------------------
// Usage: lcdDrawVerticalLine(0, 10, 239, 10, RED);
// Draws a Vertical line from (x1,y1) to (x1,y2) of the colour specified
// x2 is ignored
//-------------------------------
void lcdDrawVerticalLine(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int colour)
{
    unsigned int i;

    // If start of line is greater than end, reverse
    if (y1 > y2)
    {
        i = y1;
        y1 = y2;
        y2 = i;
    }
    lcdSetAddress(x1, y1, x1, y2);
    
    PMADDR = DATA;

    for (i = y1; i <= y2; i++)
        PMDIN = colour;
}

//-------------------------------
// Usage: lcdDrawLine(0, 10, 239, 10, RED);
// Draws a line from (x1,y1) to (x2,y2) of the colour specified
// It uses the Bresenham's line algorithm to draw the line (http://en.wikipedia.org/wiki/Bresenham's_line_algorithm)
// This function can be optimised to use only integer values.
//-------------------------------
void lcdDrawLine(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int colour)
{
    int temp = 0;

    char steep = fabs(y2 - y1) > fabs(x2 - x1); // is the line steep?

    if (steep)
    {
        // swap x1 and y1
        temp = x1;
        x1 = y1;
        y1 = temp;

        // swap x2 and y2
        temp = x2;
        x2 = y2;
        y2 = temp;
    }


     if (x1 > x2)
     {
        //swap x1 & x2
        temp = x1;
        x1 = x2;
        x2 = temp;

         //swap y1 & y2
        temp = y1;
        y1 = y2;
        y2 = temp;
     }

     int deltaX = x2 - x1;
     int deltaY = fabs(y2 - y1);

     float error = 0;
     float deltaErr = (float)deltaY / deltaX;
     int yStep;

     int x;
     int y = y1;

     if (y1 < y2) yStep = 1;
     else yStep = -1;

     for (x = x1; x<= x2;x++)
     {
         if (steep) lcdSetPixel(y, x, colour);
         else lcdSetPixel(x, y, colour);
         error += deltaErr;

         if(error >= 0.5)
         {
             y += yStep;
             error -= 1.0;
         }
     }
}


//-------------------------------
// Usage: lcdDrawRectangle(10, 13, 50, 30, RED, FILL);
// Draws a filled rectangle with vertices (10,13) to (50,30) in red
//-------------------------------
void lcdDrawRectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int colour, unsigned char filled) {
    if (filled) {
        lcdSetAddress(x1, y1, x2, y2);

        PMADDR = DATA;

        int i, j;

        for (i = x1; i <= x2; i++) {
            for (j = y1; j <= y2; j++) {
                PMDIN = colour;
            }
        }
    }
    else    // not filled
    {
        lcdDrawHorizontalLine(x1, y1, x2, y1, colour);
        lcdDrawHorizontalLine(x1, y2, x2, y2, colour);
        lcdDrawVerticalLine(x1, y1, x1, y2, colour);
        lcdDrawVerticalLine(x2, y1, x2, y2, colour);
    }
}


//-------------------------------
// Usage: lcdFillScreen(WHITE);
// Fills the screen with white
//-------------------------------
void lcdFillScreen(unsigned int colour)
{
    lcdDrawRectangle(0,0,239,319,colour,FILL);
}


//-------------------------------
// Usage: lcdDrawCircle(120, 160, 20, 1, RED);
// Purpose:       Draw a circle
// Inputs:        (x,y) - the center of the circle
//                radius - the radius of the circle
//                fill - 0 = NO, 1 = YES
//                colour - colour of circle
//-------------------------------
void lcdDrawCircle(unsigned int x, unsigned int y, int radius, int fill, unsigned int colour)
{
    signed int a, b, P;

    a = 0;
    b = radius;
    P = 1 - radius;

    do {
        if (fill) {
            lcdDrawHorizontalLine(x - a, y + b, x + a, y + b, colour);
            lcdDrawHorizontalLine(x - a, y - b, x + a, y - b, colour);
            lcdDrawHorizontalLine(x - b, y + a, x + b, y + a, colour);
            lcdDrawHorizontalLine(x - b, y - a, x + b, y - a, colour);
        } else {
            lcdSetPixel(a + x, b + y, colour);
            lcdSetPixel(b + x, a + y, colour);
            lcdSetPixel(x - a, b + y, colour);
            lcdSetPixel(x - b, a + y, colour);
            lcdSetPixel(b + x, y - a, colour);
            lcdSetPixel(a + x, y - b, colour);
            lcdSetPixel(x - a, y - b, colour);
            lcdSetPixel(x - b, y - a, colour);
        }

        if (P < 0)
            P += 3 + 2 * a++;
        else
            P += 5 + 2 * (a++ - b--);
    } while (a <= b);
}

